home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / X11 / seyon / SeTerm.c < prev    next >
C/C++ Source or Header  |  1995-05-03  |  9KB  |  357 lines

  1. /*
  2.  * This file is part of the Seyon, Copyright (c) 1992-1993 by Muhammad M.
  3.  * Saggaf. All rights reserved.
  4.  *
  5.  * See the file COPYING (1-COPYING) or the manual page seyon(1) for a full
  6.  * statement of rights and permissions for this program.
  7.  */
  8.  
  9. /*
  10.  * This file contains routines for Seyon's terminal. The main routine is
  11.  * terminal(), which reads characters from the terminal and sends them to the
  12.  * port. That routine also forks a child process that reads characters from
  13.  * the port and writes them to the temrinal. Once the parent receives SIGTERM
  14.  * (which should be sent by the grand parent), it kills the child and exits.
  15.  */
  16.  
  17. #include <stdio.h>
  18. #include <unistd.h>
  19. #include <signal.h>
  20. #include <sys/types.h>
  21. #include <sys/wait.h>
  22.  
  23. #include <X11/Intrinsic.h>
  24.  
  25. #include "seyon.h"
  26. #include "SeDecl.h"
  27.  
  28. extern char     TtyReadChar();
  29. extern int      MdmReadStr();
  30.  
  31. extern FILE    *tfp,            /* terminal pointer */
  32.                *cfp;            /* capture file pointer */
  33. extern Boolean  capture;        /* are we capturing or not ? */
  34. extern int      tfd,            /* terminal descriptor */
  35.                 mainToTermPipe[];
  36. extern pid_t    mainPid;
  37.  
  38. void            send_tbyte(),
  39.                 toggle(),
  40.                 cleanup();
  41.  
  42. pid_t           readProcPid = 0; /* pid of child process */
  43.  
  44. /*---------------------------------------------------------------------------+
  45. | DoNothingHandler - handler for doing nothing.
  46. +---------------------------------------------------------------------------*/
  47.  
  48. void
  49. DoNothingHandler(sigNum)
  50.      int       sigNum;
  51. {
  52. #ifdef DEBUG
  53.   showf(">>> in DoNothingHandler, pid = %d, sig = %d", getpid(), sigNum);
  54. #endif
  55.  
  56.   /* Reinstall the signal handler */
  57.   signal(sigNum, DoNothingHandler);
  58. }
  59.  
  60. /*---------------------------------------------------------------------------+
  61. | TerminalKillHandler - handler for the terminal kill (SIGTERM).
  62. +---------------------------------------------------------------------------*/
  63.  
  64. void
  65. TerminalKillHandler(dummy)
  66.      int             dummy;
  67. {
  68.   signal(SIGTERM, SIG_IGN);
  69.  
  70.   /* Kill the child process and wait for it to die, sounds vicious, 
  71.      doesn't it? The child process is the read process from the port */
  72.  
  73.   if (readProcPid && kill(readProcPid, SIGTERM) == 0) 
  74.     while(wait((int*)0) < 0);
  75.   
  76.   fflush(tfp);
  77.   exit(0);
  78. }
  79.  
  80. /*---------------------------------------------------------------------------+
  81. | TerminalSuspendHandler - handler for the terminal suspension (SIGUSR1).
  82. +---------------------------------------------------------------------------*/
  83.  
  84. void
  85. TerminalSuspendHandler(sigNum)
  86.      int             sigNum;
  87. {
  88.   /* Don't deliver or stack (as pending) any more instances of the signal
  89.      until we've woken up (below) */
  90.   signal(sigNum, SIG_IGN);
  91.  
  92.   if (readProcPid) kill(readProcPid, sigNum);
  93.  
  94.   pause();
  95.  
  96. #ifdef DEBUG
  97.   showf(">>> Terminal %d woke up - good", getpid());
  98. #endif
  99.  
  100.   /* After waking up */
  101.  
  102.   if (readProcPid) kill(readProcPid, SIGCONT);
  103.  
  104.   /* Reinstall the signal handler */
  105.   signal(sigNum, TerminalSuspendHandler);
  106. }
  107.  
  108. /*---------------------------------------------------------------------------+
  109. | TerminalRefreshParametersHandler - handler for the terminal to get the 
  110. |                                    current session parameters (SIGUSR2).
  111. +---------------------------------------------------------------------------*/
  112.  
  113. void
  114. TerminalRefreshParametersHandler(sigNum)
  115.      int       sigNum;
  116. {
  117.   int        PutParameters();
  118.   void       GetParameters();
  119.  
  120.   /* Don't deliver or stack (as pending) any more instances of the signal
  121.      until we're finished with the work at hand */
  122.   signal(sigNum, SIG_IGN);
  123.  
  124.   GetParameters(NULL, mainToTermPipe);
  125.  
  126.   if (readProcPid && (PutParameters(mainToTermPipe) < 0 || 
  127.                       kill(readProcPid, sigNum) != 0))
  128.     SePError("Could not pipe parameters");
  129.  
  130.   /* Reinstall the signal handler */
  131.   signal(sigNum, TerminalRefreshParametersHandler);
  132. }
  133.  
  134. /*
  135.  * Terminal: main routine. Has two processes, one to read from terminal 
  136.  *           and send to the port and the other to do the oppsite.
  137.  */
  138.  
  139. void
  140. Terminal()
  141. {
  142.   char            c;
  143.  
  144.   /* Tell the program where to go when signals are received */
  145.   signal(SIGTERM, TerminalKillHandler);
  146.   signal(SIGUSR1, TerminalSuspendHandler);
  147.   signal(SIGUSR2, TerminalRefreshParametersHandler);
  148.   signal(SIGCONT, DoNothingHandler);
  149.   signal(SIGCHLD, SIG_DFL);
  150.  
  151.   /* Split into read and write processes */
  152.  
  153.   /* Child, read proc: read from port and write to tty */
  154.   if ((readProcPid = SeFork()) == 0)
  155.     PortToTty();
  156.  
  157.   /* Parent, write proc: read from tty and write to port */
  158.  
  159.   while (1)
  160.     if (TtyReadChar(tfd, &c) >= 0) send_tbyte(c);
  161.     else {
  162.       SeError("TTY read error. Terminal process exiting");
  163.       if (readProcPid && kill(readProcPid, SIGTERM) == 0) 
  164.         while(wait((int*)0) < 0);
  165.       ProcRequest(POPUP_ERROR, "TTY Read Error", "errReadError");
  166.       exit(1);
  167.     }
  168.   /*NOT REACHED*/
  169. }
  170.  
  171. /*
  172.  * Read from the port and write to the tty
  173.  */
  174.  
  175. void
  176. PortToTty()
  177. {
  178.   static char           zmSig[] = "**\030B00";
  179.   static char          *zmSigPtr = zmSig;
  180.   char                  buf[BUFSIZ], c;
  181.   int                   n, i;
  182.  
  183.   signal(SIGTERM, TerminalKillHandler);
  184.  
  185.   /* Let the main process know we're all set */
  186.   kill(mainPid, SIGCONT);
  187.  
  188.   while (1) {
  189.  
  190.     /* Read incoming charaters and exit the process if a read error
  191.        is encountered */
  192.  
  193.     if ((n = MdmReadStr(buf)) < 0) {
  194.       SeError("Modem read error. Terminal process exiting");
  195.       ProcRequest(POPUP_ERROR, "Modem Read Error", "errReadError");
  196.       ProcRequest(KILL_TERM, "", "");
  197.       exit(1);
  198.     }
  199.  
  200.     /* Write incoming characters to the tty */
  201.     fwrite(buf, sizeof(char), n, tfp); 
  202.     fflush(tfp);
  203.  
  204.     for(i = 0; i < n; i++) {
  205.       c = buf[i];
  206.       
  207.       /* Write to capture file if capture is enabled */
  208.       if (capture) fputc(c, cfp);
  209.  
  210.       /* Look for Zmodem signature */
  211.       if (c != *zmSigPtr)
  212.         zmSigPtr = zmSig;
  213.       else if (*++zmSigPtr == '\0' && qres.autoZmodem) 
  214.         ProcRequest(DISPATCH_ACTION, "Zmodem Auto-Download", 
  215.                     qres.autoZmodemAction);
  216.  
  217.     } /* for... */
  218.   } /* while(1)... */
  219.   /*NOT REACHED*/
  220. }
  221.  
  222. /*
  223.  * send a translated character to the modem
  224.  */
  225.  
  226. void
  227. send_tbyte(c)
  228.      int             c;
  229. {
  230.   switch (c) {
  231.  
  232.     /*Translate new line to carriage return if newline translation mode is
  233.       in effect*/
  234.   case '\n':
  235.     switch (newlineTrMode) {
  236.     case 2:
  237.       c = '\r';
  238.       break;
  239.     case 3:
  240.       sendbyte('\r');
  241.     default:
  242.       break;
  243.     }
  244.     break;
  245.  
  246.     /*Translate backspace to delete if del translation mode is in effect*/
  247.   case 0x08:
  248.     if (qres.backspaceTranslation)
  249.       c = 0x7f;
  250.     break;
  251.  
  252.   default:
  253.     break;
  254.   }
  255.  
  256.   /*Send ESC before the character if meta key is pressed with the  character
  257.     and the meta key translation mode is on*/
  258.   if (qres.metaKeyTranslation && (c & 0x80)) {
  259.     sendbyte('\033');
  260.     sendbyte(c);
  261.   }
  262.  
  263.   /*Send the character to the port*/
  264.   else
  265.     sendbyte(c);
  266. }
  267.  
  268. /*---------------------------------------------------------------------------+
  269. | Routines to manipulate the terminal process. 
  270. +---------------------------------------------------------------------------*/
  271.  
  272. pid_t           termProcPid = 0; /* pid of the terminal process */
  273.  
  274. /*---------------------------------------------------------------------------+
  275. | StartTerminal - starts the terminal process.
  276. +---------------------------------------------------------------------------*/
  277.  
  278. void
  279. StartTerminal()
  280. {
  281.   /* Child Process */
  282.   if ((termProcPid = SeFork()) == 0) 
  283.     {Terminal(); exit(1);}
  284. }
  285.  
  286. /*---------------------------------------------------------------------------+
  287. | KillTerminal - kills the terminal process.
  288. +---------------------------------------------------------------------------*/
  289.  
  290. void
  291. KillTerminal()
  292. {
  293.   void     (*oldSigHandler)();
  294.  
  295.   if (termProcPid == 0) return;
  296.   /* Make sure it's not suspended so that it can react to SIGTERM */
  297. /*  if (SuspContTerminal(TERM_CONTINUE) == 0) return;*/
  298.  
  299.   oldSigHandler = signal(SIGCHLD, SIG_DFL);
  300.  
  301.   /* Kill the child and wait for it to die */
  302.   if (termProcPid && kill(termProcPid, SIGTERM) == 0) 
  303.     {while(wait((int*)0) < 0); termProcPid = 0;}
  304.  
  305.   signal(SIGCHLD, oldSigHandler);
  306. }
  307.  
  308. /*---------------------------------------------------------------------------+
  309. | SuspContTerminal - suspends or resumes the terminal process.
  310. +---------------------------------------------------------------------------*/
  311.  
  312. int
  313. SuspContTerminal(state)
  314.      int state;
  315. {
  316.   /* This variable keeps track of whether 
  317.      the terminal is active or suspended */
  318.   static int termSuspended = 0;
  319.   
  320.   if (termProcPid == 0) return 0;
  321.  
  322.   if (state == TERM_CONTINUE) {
  323.     if (termProcPid && kill(termProcPid, SIGCONT) == 0) 
  324.       termSuspended = 0;
  325.     return 1;
  326.   }
  327.  
  328.   if (termSuspended) return 0;
  329.   if (termProcPid && kill(termProcPid, SIGUSR1) == 0) 
  330.     {termSuspended = 1; return 1;}
  331.   else
  332.     return 0;
  333. }
  334.  
  335. int
  336. TerminalRefreshParameters()
  337. {
  338.   int    PutParameters();
  339.  
  340.   if (termProcPid && (PutParameters(mainToTermPipe) < 0 || 
  341.                       kill(termProcPid, SIGUSR2) != 0))
  342.     return -1;
  343.   else return 0;
  344. }
  345.  
  346. /*
  347.  * Restart the terminal process (refresh) by killing it and starting a new
  348.  * one
  349.  */
  350.  
  351. void
  352. RestartTerminal()
  353. {
  354.   KillTerminal();
  355.   StartTerminal();
  356. }
  357.